package onez.project.core.filter;

import onez.project.common.config.Rule;
import onez.project.common.constant.FilterConst;
import onez.project.core.context.GatewayContext;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * 过滤器工厂具体实现
 * 用于构造过滤器链条
 */
@Slf4j
public class GatewayFilterChainChainFactory implements FilterChainFactory {

    /**
     * 单例模式实现
     */
    private static class SingletonInstance {
        private static final GatewayFilterChainChainFactory INSTANCE = new GatewayFilterChainChainFactory();
    }

    /**
     * 获取单例实例
     * @return 单例实例
     */
    public static GatewayFilterChainChainFactory getInstance() {
        return SingletonInstance.INSTANCE;
    }

    /**
     * 使用Caffeine缓存 并且设定过期时间10min
     */
    private final Cache<String, GatewayFilterChain> chainCache = Caffeine.newBuilder().recordStats().expireAfterWrite(10,
            TimeUnit.MINUTES).build();

    /**
     * 过滤器存储映射 过滤器id - 过滤器
     */
    private final Map<String, Filter> processorFilterIdMap = new ConcurrentHashMap<>();

    /**
     * 构造函数 - 初始化网关过滤器链工厂
     *
     * 功能描述：
     * 1. 使用Java SPI机制加载所有Filter接口的实现类
     * 2. 解析每个过滤器的@FilterAspect注解信息
     * 3. 构建过滤器ID与过滤器实例的映射关系
     *
     * 实现逻辑：
     * - 通过ServiceLoader动态加载所有Filter实现类
     * - 遍历每个过滤器实例，获取其元数据注解
     * - 生成唯一过滤器ID（优先使用注解ID，类名作为兜底）
     * - 将过滤器注册到处理器映射表中
     */
    public GatewayFilterChainChainFactory() {
        // 使用Java SPI机制加载所有过滤器实现
        ServiceLoader<Filter> serviceLoader = ServiceLoader.load(Filter.class);

        // 遍历所有发现的过滤器实现类
        serviceLoader.stream().forEach(filterProvider -> {
            Filter filter = filterProvider.get();
            // 解析过滤器元数据注解
            FilterAspect annotation = filter.getClass().getAnnotation(FilterAspect.class);

            // 记录过滤器加载日志（类信息+注解元数据）
            log.info("load filter success:{},{},{},{}", filter.getClass(), annotation.id(), annotation.name(),
                    annotation.order());

            // 构建过滤器唯一标识：优先使用注解ID，未配置时使用类全限定名
            String filterId = annotation.id();
            if (StringUtils.isEmpty(filterId)) {
                filterId = filter.getClass().getName();
            }

            // 注册过滤器到全局映射表
            processorFilterIdMap.put(filterId, filter);
        });
    }


    /**
     * 构建过滤器链
     * @param ctx 网关上下文
     * @return 过滤器链
     */
    @Override
    public GatewayFilterChain buildFilterChain(GatewayContext ctx) {
        return chainCache.get(ctx.getRule().getId(),k->doBuildFilterChain(ctx.getRule()));
    }

    /**
     * 实际构建过滤器链的逻辑
     * @param rule 规则
     * @return 过滤器链
     */
    //TODO 为什么要手动一个个加过滤器？
    public GatewayFilterChain doBuildFilterChain(Rule rule) {
        GatewayFilterChain chain = new GatewayFilterChain();
        List<Filter> filters = new ArrayList<>();
        //手动将某些过滤器加入到过滤器链中
        filters.add(getFilterInfo(FilterConst.GRAY_FILTER_ID));
        filters.add(getFilterInfo(FilterConst.MOCK_FILTER_ID));
        if (rule != null) {
            Set<Rule.FilterConfig> filterConfigs = rule.getFilterConfigs();
            Iterator<Rule.FilterConfig> iterator = filterConfigs.iterator();
            Rule.FilterConfig filterConfig;
            while (iterator.hasNext()) {
                filterConfig = iterator.next();
                if (filterConfig == null) {
                    continue;
                }
                String filterId = filterConfig.getId();
                if (StringUtils.isNotEmpty(filterId) && getFilterInfo(filterId) != null) {
                    Filter filter = getFilterInfo(filterId);
                    filters.add(filter);
                }
            }
        }
        //添加路由过滤器-这是最后一步
        filters.add(getFilterInfo(FilterConst.ROUTER_FILTER_ID));
        //排序
        filters.sort(Comparator.comparingInt(Filter::getOrder));
        //添加到链表中
        chain.addFilterList(filters);
        return chain;
    }

    /**
     * 根据过滤器ID获取过滤器实例
     * @param filterId 过滤器ID
     * @return 过滤器实例
     */
    @Override
    public Filter getFilterInfo(String filterId) {
        return processorFilterIdMap.get(filterId);
    }
}
